Skip to main content

3.3 API Integration

On top of providing user flow for managing the link shortener, Blink also allows APIs to integrate with it via OAuth2. More specifically, this means that you can configure Blink to be called by not just session-based users who are using it via the web portal (the UI), but also to be called by external APIs in a controllable manner so that you may write APIs that "integrate" with Blink without exposing Blink's APIs, unprotected, to the entirety of the internet.

Configuration

First off, breathe.

All of the OAuth2 configuration is done by the OAUTH2_ prefixed environment variables as you may see in the .env file.

First, note that OAUTH2_ENABLED is, by default, set to true. Set it to false if you don't plan on exposing the API via OAuth2.

The algorithms, audience, and the issuer should be copy-pasted from your authorization server. Note that the algorithms variable is a comma-separated "list" of all the algorithms the authorization server allows that you want to use (e.g. RS256,RS512).

The OAUTH2_JWT_SECRET and OAUTH2_JWKS_* variables are mutually exclusive. The former allows you to simply decode the JWTs that the APIs present using a string or a key that the authorization server and Blink share; for symmetric encryption algorithms such as HS256, this would be the actual private key. For asymmetric ones, it would be the public key, as verification of the JWT is possible without having the key that it was encrypted with.

The latter allows you to dynamically load in the shared secret to verify the JWTs; this would be useful if, for example, your authorization server had a rotating set of keys to encrypt and verify the JWTs against, so that Blink can "pick up" on those rotating set of keys without having to hard code them. See https://github.com/auth0/express-jwt#multi-tenancy for more details.

And finally, the OAUTH2_DEFAULT_SCOPE describes the default scope the JWTs will be assigned if the JWT is missing the scope claim. It is a space-separated "list" of the scopes, and the * serves as a wildcard; so, for example, link:* would include link:create, link:read, link:update, and link:delete.

Of note, these scopes restrict what an authorized API could do on top of the built-in policies that dictate what a superuser can and cannot do (it's not an either/or). So, for example, even with a link:update scope, you cannot update the shortened link after it's already been set.

Recommendations

First off, I understand that OIDC is a protocol built on top of OAuth2; however, I suggest that you do not re-use the OIDC provider that you use as the "user pool" as the authorization server as well. Just, don't.

In addition, always always always be sure to fill out the audience and issuer for additional security. Not all authorization servers might outright tell you what these values are; a good way to figure this out is to paste a sample token from the authorization server onto https://jwt.io or something similar and seeing the scopes for those two in the decoded payload.

As for secrets, if you're using OAUTH2_JWT_SECRET, please do use a long string (at least 32 characters); if not (and this depends on what your authorization server supports), it's best to rely on JWKS to rotate actual keys. Not only is it more robust, but it also allows the authorization server to "rotate" keys that it signs the JWTs with so that should any specific key be compromised, it can quickly "advertise" to its dependents (including Blink) to not use that key to validate.

And finally, try if possible to set the scope in JWTs; obviously, this depends on whether your authorization server supports it, but please do it if you can. In addition, always set the scope to the bare minimum to support a consuming API's operations. If it doesn't need to read the users, then don't include the user:read scope, and such.